const express = require("express");
const logger = require("morgan");
const bodyParser = require("body-parser");
const cors = require("cors");
//引入数据库模型
const { UserAction, ErrorLog, VisitLog, UserLog } = require("./models/index");
const app = express();

// 它会将应用程序的请求信息输出到控制台，日志格式为"dev"。
app.use(logger("dev"));

//它用于解析传入请求的JSON数据，并将其转换为JavaScript对象。
app.use(bodyParser.json());

//用于解析传入请求的文本数据。
app.use(bodyParser.text());
// 表示对所有的请求路径都启用跨域资源共享
app.all("/*", cors());

// 获取uv统计
app.use("/api/get/pvuv", async (req, res) => {
  const uv = await UserLog.find().count();
  res.json({
    uv,
  });
});

// 行为日志
app.use("/api/get/userAction", async (req, res) => {
  // 获取页码数
  const page = req.query.page;
  // 获取总数
  const total = await UserAction.find().count();
  const data = await UserAction.find()
    // 按照createTime字段倒序排序，
    .sort({ createTime: -1 })
    // 然后限制返回10条记录
    .limit(10)
    // 从第0页开始
    .skip(10 * (page - 1));
  res.json({
    total,
    // 将总记录数total除以每页显示的记录数10，然后向上取整，
    pages: Math.ceil(total / 10),
    data,
  });
});
// 错误日志
app.use("/api/get/errorLog", async (req, res) => {
  const page = req.query.page;
  const total = await ErrorLog.find().count();
  const data = await ErrorLog.find()
    .sort({ createTime: -1 })
    .limit(10)
    .skip(10 * (page - 1));
  res.json({
    total,
    pages: Math.ceil(total / 10),
    data,
  });
});

// 访问日志
app.use("/api/get/visitLog", async (req, res) => {
  const page = req.query.page;
  const total = await VisitLog.find().count();
  const data = await VisitLog.find()
    .sort({ createTime: -1 })
    .limit(10)
    .skip(10 * (page - 1));
  res.json({
    total,
    pages: Math.ceil(total / 10),
    data,
  });
});

app.use("/report/actions", (req, res) => {
  const logs = typeof req.body === "object" ? req.body : JSON.parse(req.body);

  logs?.forEach(async (item) => {
    const log = JSON.parse(item);
    const { appId, userId, type, data, currentTime, currentPage, ua } = log;

    switch (type) {
      // 错误日志上报
      case "error":
        const errorLog = new ErrorLog({
          appId,
          userId,
          errorType: data.errorType,
          errMsg: data.message,
          error: data.error,
          col: data.col,
          row: data.row,
          createTime: currentTime,
          currentPage,
          ua,
        });
        await errorLog.save();
        break;
      // 无痕埋点
      case "action":
        const userAction = new UserAction({
          appId,
          userId,
          actionType: data.actionType,
          data: data.data,
          createTime: currentTime,
          currentPage,
          ua,
        });
        await userAction.save();
        break;
      //页面停留统计
      case "visit":
        const visitLog = new VisitLog({
          appId,
          userId,
          stayTime: data.stayTime,
          createTime: currentTime,
          currentPage: data.page,
          ua,
        });
        if (!data.page) {
          return;
        }
        await visitLog.save();
        break;
      // 统计用户
      case "user":
        // 它会查找具有特定userId和appId的用户记录
        const target = await UserLog.find({ userId, appId });
        //如果没有就添加
        if (target?.length === 0) {
          const userLog = new UserLog({
            appId,
            userId,
            ua,
          });
          await userLog.save();
        }
        break;
      default:
        break;
    }
  });
  res.send("发送成功");
});

// 当请求无法匹配任何路由时，会创建一个状态码为404的错误对象，并将其传递给下一个中间件。
app.use(function (req, res, next) {
  const err = new Error("Not Found");
  err.status = 404;
  next(err);
});

//第二个app.use函数是用来处理错误的中间件
app.use(function (err, req, res, next) {
  res.locals.message = err;

  res.locals.error = req.app.get("env") === "development" ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.json({
    code: "error",
    info: err,
  });
});

const port = process.env.PORT || 5001;
app.listen(port, () => {
  console.log(`server is running on port ${port}`);
});

require("./db");
